#pragma once
#include<iostream>
#include<vector>
#include<queue>
#include<condition_variable>
#include<mutex>
#include<thread>
#include<memory>
#include<functional>


class ThreadPool
{
public:
	ThreadPool(size_t nums = std::thread::hardware_concurrency()):_isrunning(false)
	{
		for (int i = 0; i < nums; i++)
		{
			_threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this));
		}
	}

	template<class F,class... Args>
	void EnQueue(F&&f,Args&&...args)
	{
		{
			std::unique_lock<std::mutex> lock(_mutex);
			_tasks.emplace(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
		}
		_cond.notify_one();

	}
	~ThreadPool()
	{
		{
			std::unique_lock<std::mutex> lock(_mutex);
			_isrunning = false;
		}
		_cond.notify_all();
		for (auto& thread: _threads)
		{
			if (thread.joinable())
				thread.join();
		}
	}
private:
	void HandlerTask()
	{
		while (1)
		{
			std::function<void()> task;
			{
				std::unique_lock<std::mutex> lock(_mutex);
				_cond.wait(lock, [this] {return !_isrunning || !_tasks.empty(); });
				if (!_isrunning && _tasks.empty())
					return;
				task = _tasks.front();
				_tasks.pop();
			}
			task();
		}
	}
	std::vector<std::thread> _threads;
	std::queue<std::function<void()>> _tasks;
	std::mutex _mutex;
	std::condition_variable _cond;
	bool _isrunning;
};